#!/usr/bin/env python

##HACKABOT_HELP##
# Bookmark a URL to del.icio.us
# !bookmark [url] [[-t] tag (tag..)] [-d short description] [-e extended description]
##HACKABOT_HELP##

import sys
import os
import re
import urllib
from urlparse import urlparse

import hackabot
from hackabot.client import Client

def sendToDelicious(url, tags, description, extended, username, password):
    # no quotes (and spaces) allowed, but everything else
    tags = [tag.strip('"') for tag in tags]
    if not description:
        description = beautifyURL(url)
    if not extended:
        extended = ''

    params = { 'url' : url,
               'description': description,
               'extended': extended,
               'tags': " ".join(tags),
               'replace': 'no' }
    paramstring = urllib.urlencode(params)

    opener = EvenFancierURLopener(username, password)
    api = opener.open("https://api.del.icio.us/v1/posts/add?%s" % paramstring)
    if not api:
        return "Error: The del.icio.us API could not be accessed!"
    retval = api.read()

    if not retval:
        return "Error: The del.icio.us server did not answer anything"

    parsedresult = re.search(r'result code="([^"]+)"', retval)
    if parsedresult:
        code = parsedresult.group(1)
        if code == 'done':
            return 'Successfully bookmarked.'
        else:
            return 'Oops, del.icio.us said: "%s"' % code

    # last resort. If we reach this, something bad happened.
    return 'Invalid server reply (%s...)' % retval[:200]

class EvenFancierURLopener(urllib.FancyURLopener):
    """override fancyurlopener to pass on the right user and pass"""
    version = "Hackabot %s" % hackabot.__version__ # user agent

    def __init__(self, username, password):
        self.user = username
        self.passwd = password
        urllib.FancyURLopener.__init__(self)

    def prompt_user_passwd(self, host, realm):
        return (self.user, self.passwd)

def beautifyURL(url):
    """for description: remove http and stuff"""
    tuple = urlparse(url)
    if not tuple: return url
    return urllib.unquote(tuple[1]+tuple[2])


def parse(msg):
    # let's do all sorts of fuzzy parsing for the alternative syntaxes
    allparams = msg.split()
    url = allparams[0]

    allparams = allparams[1:]
    # valid  states
    states = { '-t': 'tag',
               '-d': 'desc',
               '-e': 'ext' }
    curstate = 'tag' # if you don't specify flags, you're adding tags only
    quoted = False # start off unquoted. "Quoted" mode ignores possible flags
    tags = []
    desc = []
    extended = []
    for token in allparams:
        if not quoted:
            try:
                c = states[token.lower()[:2]]
            except:
                c = None
            if c:
                curstate = c
                token = token[2:]
                if not token: continue
            if token[0] == '"' and curstate != 'tag':
                # start quoted mode
                quoted = True
                token = token[1:]
            if token[-1] == '"' and curstate != 'tag':
                quoted = False
                token = token[:-1]
        else:
            if token[-1] == '"':
                quoted = False
                token = token[:-1]

        if curstate == 'tag':
            tags.append(token)
        elif curstate == 'desc':
            desc.append(token)
        elif curstate == 'ext':
            extended.append(token)

    return (url, tags, " ".join(desc), " ".join(extended))

def main():
    hbc = Client()
    config = hbc.conf.find(".//commands/bookmark")

    if config is None:
        print "send bookmark has not been configured!"
        sys.exit();

    username = config.get("username")
    password = config.get("password")

    msg = hbc.readline()
    nick = hbc.sent_by()
    chan = hbc.channel()

    if not msg:
        if chan:
            path = chan
        else:
            path = "user.%s" % nick

        print "send %s: Check out http://del.icio.us/%s/%s" % (username, path)

    else:
        (url, tags, desc, extended) = parse(msg)

        if chan:
            tags.append(chan)

        tags.append("user."+nick)

        # now bookmark and we're all set.
        result = sendToDelicious(url, tags, desc, extended, username, password)
        print "send %s: %s" % (nick, result)

if __name__ == "__main__":
    main()
